package zdream.pmfield.doc.generator;

import java.io.File;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import zdream.pmfield.data.foe.MoveCheckPair;
import zdream.pmfield.data.foe.MoveTemplate;
import zdream.pmfield.data.foe.Type;
import zdream.pmfield.data.foe.VStat;
import zdream.pmfield.doc.translator.MoveTermTranslator;
import zdream.pmfield.storage.FoeTemplateStorage;

import static zdream.pmfield.doc.translator.MoveTermTranslator.*;

/**
 * @author Zdream
 * @date 2023-11-29
 * @since 0.0.1
 */
public class MoveDocumentGenerator {
	public final File moveDocPath;
	private final FoeTemplateStorage storage;

	public boolean skipExistsMoveFile = false;

	public MoveDocumentGenerator(File moveDocPath) {
		this.moveDocPath = Objects.requireNonNull(moveDocPath);

		storage = new FoeTemplateStorage();
		storage.load();
	}

	public static void main(String[] args) {
		final File moveDocPath = createMoveDocRootFile();
		new MoveDocumentGenerator(moveDocPath).generateAll();
	}

	private static File createMoveDocRootFile() {
		final String dir = System.getProperty("user.dir");
		final Path rootPath = Paths.get(dir); // , "doc", "moves"
		final File root = rootPath.toFile();

		if (!root.exists() || !root.isDirectory()) {
			throw new IllegalArgumentException("user.dir is invalid: " + root);
		}

		Path moveDocPath = rootPath
				.resolve("src")
				.resolve("test")
				.resolve("resources")
				.resolve("doc")
				.resolve("moves");
		File moveDocFile = moveDocPath.toFile();

		if (!moveDocFile.exists()) {
			final boolean success = moveDocFile.mkdirs();
			if (!success) {
				throw new IllegalStateException("failed to create directory: " + moveDocFile);
			}
		}

		return moveDocFile;
	}

	public void generateAll() {
		final List<MoveTemplate> allMoves = storage.findAllMoves();

		final int[] idArray = allMoves.stream()
				.mapToInt(move -> move.id)
				.distinct()
				.sorted()
				.toArray();
		for (int id : idArray) {
			List<MoveTemplate> moves = allMoves.stream()
					.filter(move -> move.id == id)
					.collect(Collectors.toList());
			generateForMoves(id, moves);
		}
	}

	public void generateForMoves(int id, List<MoveTemplate> moves) {
		final MoveTemplate first = moves.iterator().next();
		String directoryName = String.format("%05d-%s", id, first.name);

		File directory = moveDocPath.toPath().resolve(directoryName).toFile();
		if (!directory.exists()) {
			boolean success = directory.mkdir();
			if (!success) {
				System.err.println("创建目录失败: " + directory);
				return;
			}
			System.out.println("创建目录: " + directory);
		} else {
			System.out.println("目录已存在: " + directory);
		}

		// 创建子文件
		for (MoveTemplate move : moves) {
			generateForMove(directory, move);
		}
	}

	public void generateForMove(File directory, MoveTemplate move) {
		String fileName = String.format("lv%d.md", move.level);
		final Path path = directory.toPath().resolve(fileName);

		// TODO 已有的文件就跳过
		if (skipExistsMoveFile && Files.exists(path)) {
			System.out.println("文件: " + path + " 已存在");
			return;
		}

		StringBuilder builder = new StringBuilder(1280);
		builder.append('\n');

		builder.append("# 技能: ").append(move.name).append('\n');
		builder.append('\n');
		builder.append("### 基础参数").append('\n');
		builder.append('\n');
		builder.append("|键|值|").append('\n');
		builder.append("|---|---|").append('\n');
		builder.append("|ID|").append(move.id).append('|').append('\n');
		builder.append("|名称|").append(move.name).append('|').append('\n');
		builder.append("|等级|").append(move.level).append('|').append('\n');
		builder.append("|主属性|").append(typeName(move.mainType())).append('|').append('\n');
		builder.append("|属性|").append(moveTypesDoc(move)).append('|').append('\n');
		builder.append("|类型|").append(moveUsingDoc(move)).append('|').append('\n');
		builder.append('\n');
		builder.append("### 检定参数").append('\n');
		builder.append('\n');
		builder.append(vStatDoc(move));
		builder.append('\n');
		builder.append("技能效果如下表所示").append('\n');
		builder.append('\n');
		builder.append(moveCheckPairDoc(move));
		builder.append('\n');
		builder.append("精准度修正: ").append(move.checkRateFixed).append('\n');


		try {
			Files.write(path, builder.toString().getBytes(StandardCharsets.UTF_8));
			System.out.println("生成文件: " + path);
		} catch (IOException e) {
			System.out.println("生成文件 " + path + " 失败"); // 这段用 out 确保和其它 out 的输出顺序
			e.printStackTrace();
		}
	}

	private static String moveTypesDoc(MoveTemplate move) {
		StringBuilder builder = new StringBuilder(36);

		for (Type.TypeWithWeight type : move.types) {
			builder.append(typeName(type.type)).append(' ').append('(');
			int weight = (int) (type.weight * 100f / Type.TypeWithWeight.WEIGHT_FULL + 0.5);
			builder.append(weight).append('%').append(')').append(' ');
		}
		builder.deleteCharAt(builder.length() - 1);
		return builder.toString();
	}

	private static String moveUsingDoc(MoveTemplate move) {
		if (move.attackerUsing == move.defenseUsing) {
			return moveTypeName(move.attackerUsing);
		}

		return String.format("%s (防御方视为%s)", move.attackerUsing, move.defenseUsing);
	}

	private static String vStatDoc(MoveTemplate move) {
		if (move.vStats.length == 0) {
			return "无\n";
		}

		StringBuilder builder = new StringBuilder(128);
		for (VStat vStat : move.vStats) {
			builder.append('*').append(' ').append(vStatName(vStat)).append('\n');
		}
		return builder.toString();
	}

	private static String moveCheckPairDoc(MoveTemplate move) {
		final MoveCheckPair[] pairs = move.pairs;
		StringBuilder builder = new StringBuilder(128);

		builder.append("|成功点数|判定|技能威力|附加效果|").append('\n');
		builder.append("|---|---|---|---|").append('\n');

		MoveCheckPair morePair = null;

		for (MoveCheckPair pair : pairs) {
			if (pair.level == MoveCheckPair.LEVEL_MORE) {
				morePair = pair;
				continue;
			}

			builder.append('|').append(pair.level).append('|');

			switch (pair.result) {
			case MoveCheckPair.RESULT_MAJOR_SUCCESS: builder.append("大成功"); break;
			case MoveCheckPair.RESULT_SUCCESS: builder.append("成功"); break;
			case MoveCheckPair.RESULT_FAILURE: builder.append("失败"); break;
			case MoveCheckPair.RESULT_MAJOR_FAILURE: builder.append("大失败"); break;
			}

			builder.append('|').append(pair.power).append('|');
			builder.append(movePairAdditionDoc(pair));
			builder.append('|').append('\n');
		}

		if (morePair == null) {
			return builder.toString();
		}

		builder.append('\n');
		builder.append("如果点数超过 ").append(move.vStats.length).append('\n');
		builder.append('\n');
		builder.append("|技能威力|附加效果|").append('\n');
		builder.append("|---|---|").append('\n');
		builder.append('|');
		builder.append("每超过 1 点数, 威力 ").append(morePair.power < 0 ? "" : "+").append(morePair.power);
		builder.append('|');
		builder.append(movePairAdditionDoc(morePair));
		builder.append('|').append('\n');

		return builder.toString();
	}

	private static String movePairAdditionDoc(MoveCheckPair pair) {
		if (pair.additions == null) {
			return "无";
		}

		String[] texts = Arrays.stream(pair.additions)
				.map(MoveTermTranslator::effectName)
				.toArray(String[]::new);
		return String.join("; ", texts);
	}
}
